package system

import (
	"gin-admin/common/dto/response"
	"gin-admin/core"
	"gin-admin/model"
	"gin-admin/repo"
	serviceRequest "gin-admin/service/dto/request"

	"gorm.io/gorm"
)

type UserRoleService struct {
	UserRepository *repo.Repository[model.User]
	RoleRepository *repo.Repository[model.Role]
	Repository     *repo.Repository[model.UserRole]
}

func NewUserRoleServiceApp(
	userRepository *repo.Repository[model.User],
	roleRepository *repo.Repository[model.Role],
	repository *repo.Repository[model.UserRole],
) *UserRoleService {
	return &UserRoleService{
		UserRepository: userRepository,
		RoleRepository: roleRepository,
		Repository:     repository,
	}
}

func (urs *UserRoleService) CreateUserRoleInfoService(requestData *serviceRequest.CreateOrModifyUserRoleRequest) *response.ServiceError {
	if err := urs.checkUserExistsWithUserId(requestData.UserID); err != nil {
		return err
	}
	existsRoleMap, err := urs.RoleRepository.CheckDataBatchExistsByIds(requestData.Roles)
	if err != nil {
		return err
	}
	err = core.UseTransactionWith(urs.Repository.DB, func(tx *gorm.DB) *response.ServiceError {
		for _, roldId := range requestData.Roles {
			if !existsRoleMap[roldId] {
				continue
			}
			condition := map[string]interface{}{
				"user_id": requestData.UserID,
				"role_id": roldId,
			}
			userRole := model.UserRole{
				UserID: requestData.UserID,
				RoleID: roldId,
			}
			if err := urs.Repository.GenericCreateRelationshipDataWithTransaction(tx, &userRole, condition, urs.userRoleExistsHandler); err != nil {
				return err
			}
		}
		return nil
	})
	return err
}

func (urs *UserRoleService) DeleteUserRoleInfoService(id string) (bool, *response.ServiceError) {
	return urs.Repository.GenericLogicDeleteById(id, "", urs.userRoleNotFoundHandler)
}

func (urs *UserRoleService) ModifyUserRoleInfoService(requestData *serviceRequest.CreateOrModifyUserRoleRequest) (bool, *response.ServiceError) {
	if err := urs.checkUserExistsWithUserId(requestData.UserID); err != nil {
		return false, err
	}
	existsRoleMap, err := urs.RoleRepository.CheckDataBatchExistsByIds(requestData.Roles)
	if err != nil {
		return false, err
	}
	if err := core.UseTransactionWith(urs.Repository.DB, func(tx *gorm.DB) *response.ServiceError {
		for _, roleId := range requestData.Roles {
			if !existsRoleMap[roleId] {
				continue
			}
			condition := map[string]interface{}{
				"user_id": requestData.UserID,
				"role_id": roleId,
			}
			userRole := model.UserRole{
				UserID: requestData.UserID,
				RoleID: roleId,
			}
			if err := urs.Repository.GenericModifyRelationshipDataWithTransaction(tx, &userRole, condition, urs.userRoleExistsHandler); err != nil {
				return err
			}
			return nil
		}
		return nil
	}); err != nil {
		return false, err
	}
	return true, nil
}

func (urs *UserRoleService) userNotFoundHandler() *response.ServiceError {
	return response.WrapError(
		response.UserNotFoundCode,
		response.GetStatusCode(response.UserNotFoundCode).Message,
	)
}

func (urs *UserRoleService) userRoleNotFoundHandler() *response.ServiceError {
	return response.WrapError(
		response.UserRoleNotFoundCode,
		response.GetStatusCode(response.UserRoleNotFoundCode).Message,
	)
}

func (urs *UserRoleService) userRoleExistsHandler() *response.ServiceError {
	return response.WrapError(
		response.UserRoleExistsCode,
		response.GetStatusCode(response.UserRoleExistsCode).Message,
	)
}

func (urs *UserRoleService) checkUserExistsWithUserId(userId string) *response.ServiceError {
	condition := map[string]interface{}{
		"user_id": userId,
	}
	exists, err := urs.UserRepository.CheckDataExistsByCondition(condition, "")
	if err != nil {
		return err
	}
	if !exists {
		return urs.userNotFoundHandler()
	}
	return nil
}
